#!/usr/bin/env python
# -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt

def explain_convolution_process():
    """Detailed explanation of convolution calculation process"""
    print("\n========== CONVOLUTION CALCULATION PROCESS ==========\n")
    
    print("1. WHAT IS CONVOLUTION?")
    print("   Convolution is a mathematical operation that combines two functions f and g")
    print("   to produce a third function that represents how one function modifies the shape of the other.")
    print("\n   In signal processing: Output of a system when a signal passes through it")
    print("   In image processing: Used for filtering, edge detection, etc.")
    print("\n   Mathematical definition:")
    print("   (f * g)(t) = integral [f(tau) * g(t-tau)] d(tau)")
    print("   Where: * represents convolution, tau is dummy variable, t is output time variable")
    
    print("\n2. DISCRETE CONVOLUTION STEPS:")
    print("   For discrete signals, convolution can be broken down into 5 steps:")
    print("   a. REVERSE: Flip the second signal (kernel/filter) in time")
    print("   b. SHIFT: Slide the reversed kernel along the input signal")
    print("   c. MULTIPLY: At each position, multiply corresponding elements")
    print("   d. SUM: Add all products to get the convolution value at that position")
    print("   e. REPEAT: Move to next position and repeat steps c and d")
    
    # Demonstrate with simple example
    demonstrate_simple_example()
    
    # Visualize convolution steps
    visualize_convolution_steps()
    
    print("\n3. INTUITIVE UNDERSTANDING:")
    print("   Convolution is essentially a weighted average operation")
    print("   - Each output value is a weighted sum of signal values in a local region")
    print("   - The kernel determines how to 'sense' different features of the signal")
    print("   - Special kernels like Mexican hat wavelet detect specific features")
    
    print("\n4. CONVOLUTION VS CORRELATION:")
    print("   - Convolution requires flipping the kernel, correlation does not")
    print("   - Correlation measures similarity between signals")
    print("   - Convolution measures how one signal affects another")
    
    print("\n5. MEXICAN HAT WAVELET SIGNIFICANCE:")
    print("   - Second derivative of Gaussian function")
    print("   - Sensitive to rapid changes in signals")
    print("   - Positive part responds to convex changes")
    print("   - Negative part responds to concave changes")
    print("   - Effective for detecting peaks and edges")

def demonstrate_simple_example():
    """Demonstrate convolution with simple arrays"""
    print("\n3. SIMPLE EXAMPLE CALCULATION:")
    
    # Define simple signal and kernel
    signal = [1, 2, 3, 4]
    kernel = [0.5, 1, 0.5]
    
    print(f"   Signal: {signal}")
    print(f"   Kernel: {kernel}")
    
    # Step 1: Reverse the kernel
    reversed_kernel = kernel[::-1]
    print(f"   Step 1 - Reverse kernel: {reversed_kernel}")
    
    # Perform convolution calculation
    n = len(signal)
    m = len(kernel)
    conv_result = []
    
    print("   Steps 2-4 - Shift, Multiply, Sum:")
    
    # Calculate each convolution value
    for i in range(n + m - 1):
        # Calculate overlapping region
        start = max(0, i - m + 1)
        end = min(i + 1, n)
        
        # Get values for calculation
        signal_vals = signal[start:end]
        kernel_start = max(0, m - i - 1)
        kernel_vals = reversed_kernel[kernel_start:kernel_start + len(signal_vals)]
        
        # Calculate sum of products
        product_sum = sum(s * k for s, k in zip(signal_vals, kernel_vals))
        conv_result.append(product_sum)
        
        # Show detailed calculation
        products = [f"{s}*{k}={s*k:.1f}" for s, k in zip(signal_vals, kernel_vals)]
        print(f"   Position {i+1}: signal_part = {signal_vals}, kernel_part = {kernel_vals}")
        print(f"         products = {products}")
        print(f"         sum = {product_sum:.1f}")
    
    print(f"\n   Final convolution result: {conv_result}")

def visualize_convolution_steps():
    """Visualize convolution calculation steps"""
    # Create simple signal and kernel
    signal = np.array([0, 0, 1, 2, 1, 0, 0])
    kernel = np.array([1, -1])
    reversed_kernel = np.flip(kernel)
    
    # Calculate convolution result
    n = len(signal)
    m = len(kernel)
    conv_result = np.zeros(n + m - 1)
    
    # Create figure
    fig, axes = plt.subplots(min(5, len(conv_result)), 1, figsize=(10, 3 * min(5, len(conv_result))))
    if len(conv_result) == 1:
        axes = [axes]
    
    # Visualize key steps
    for i in range(min(5, len(conv_result))):  # Show first 5 positions
        ax = axes[i]
        
        # Plot original signal
        ax.stem(range(len(signal)), signal, 'b-', markerfmt='bo', linefmt='b-', basefmt='k-', label='Signal')
        
        # Calculate kernel positions
        kernel_positions = np.arange(i - m + 1, i + 1)
        valid_pos = (kernel_positions >= 0) & (kernel_positions < len(signal))
        
        # Plot kernel positions
        if np.any(valid_pos):
            kernel_values = np.zeros(len(signal))
            kernel_values[kernel_positions[valid_pos]] = reversed_kernel[valid_pos]
            ax.stem(range(len(signal)), kernel_values, 'r-', markerfmt='ro', linefmt='r-', basefmt='k-', label='Kernel')
            
            # Calculate product
            product = signal * kernel_values
            ax.bar(range(len(signal)), product, color='g', alpha=0.3, label='Product')
            
            # Calculate convolution value
            conv_val = np.sum(product)
            conv_result[i] = conv_val
            ax.set_title(f'Step {i+1}: Convolution = {conv_val:.2f}')
        else:
            ax.set_title(f'Step {i+1}: No overlap')
        
        ax.grid(True, alpha=0.3)
        ax.legend()
    
    # Plot final convolution result
    plt.figure(figsize=(10, 4))
    plt.stem(range(len(conv_result)), conv_result, 'g-', markerfmt='go', linefmt='g-', basefmt='k-')
    plt.title('Final Convolution Result')
    plt.grid(True, alpha=0.3)
    plt.savefig('convolution_steps_visualization.png')
    plt.close()
    
    print("\n4. VISUALIZATION EXPLANATION:")
    print("   Generated 'convolution_steps_visualization.png' showing key convolution steps")
    print("   Blue: Original signal")
    print("   Red: Reversed kernel positions")
    print("   Green: Product results at each position")
    print("   Title shows convolution value at that step")

def main():
    print("Explaining convolution calculation process in detail...")
    explain_convolution_process()
    print("\nExplanation completed!")

if __name__ == "__main__":
    main()